package parser;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.StringTokenizer;

import structs.Matrix;
import structs.Vector3;
import worldobjects.TriangleMesh;

public class ObjParser {

	private final String VERTEX = "v";
	private final String FACE = "f";
	private final String TEXCOORD = "vt";
	private final String NORMAL = "vn";
	private final String OBJECT = "o";
	private final String MATERIAL_LIB = "mtllib";
	private final String USE_MATERIAL = "usemtl";
	private final String NEW_MATERIAL = "newmtl";
	private final String DIFFUSE_COLOR = "Kd";
	private final String DIFFUSE_TEX_MAP = "map_Kd";

	// protected Resources resources;
	// protected String resourceID;
	// protected String packageID;
	// protected String currentMaterialKey;
	/*
	 * protected ArrayList<ParseObjectData> parseObjects; protected
	 * ParseObjectData co; protected boolean firstObject; protected TextureAtlas
	 * textureAtlas; protected ArrayList<Number3d> vertices; protected
	 * ArrayList<Uv> texCoords; protected ArrayList<Number3d> normals; protected
	 * boolean generateMipMap; protected HashMap<String, Material> materialMap;
	 */

	private ArrayList<Vector3> vertices = new ArrayList<Vector3>();
	private ArrayList<Vector3> normals = new ArrayList<Vector3>();
	private ArrayList<ParsedFace> faces = new ArrayList<ParsedFace>();

	/**
	 * TODO: support multiple objects TODO: support non-triangles (maybe)
	 * 
	 * @param fileStream
	 */
	public void parse(InputStream fileStream) {
		long startTime = Calendar.getInstance().getTimeInMillis();

		BufferedReader buffer = new BufferedReader(new InputStreamReader(fileStream));
		String line;

		try {
			while ((line = buffer.readLine()) != null) {
				// remove duplicate whitespace
				// line = line.replaceAll("\\s+", " ");
				// String[] parts = line.split(" ");
				StringTokenizer parts = new StringTokenizer(line, " ");
				int numTokens = parts.countTokens();
				if (numTokens == 0)
					continue;
				String type = parts.nextToken();

				if (type.equals(VERTEX)) {
					float x = Float.parseFloat(parts.nextToken());
					float y = Float.parseFloat(parts.nextToken());
					float z = Float.parseFloat(parts.nextToken());
					vertices.add(new Vector3(x, y, z));
				} else if (type.equals(FACE)) {

					ParsedFace face = new ParsedFace();

					String next;
					while (parts.hasMoreTokens()) {
						next = parts.nextToken();
						StringTokenizer subParts = new StringTokenizer(next, "/");
						int v = Integer.parseInt(subParts.nextToken());
						int vt = 0;
						int vn = 0;
						if (subParts.hasMoreTokens())
							vt = Integer.parseInt(subParts.nextToken());
						if (subParts.hasMoreTokens())
							vn = Integer.parseInt(subParts.nextToken());
						face.addEntry(v, vt, vn);
					}

					faces.add(face);
				} /*
				 * else if (type.equals(TEXCOORD)) { Uv texCoord = new Uv();
				 * texCoord.u = Float.parseFloat(parts.nextToken()); texCoord.v
				 * = Float.parseFloat(parts.nextToken()) * -1f;
				 * texCoords.add(texCoord); }
				 */

				else if (type.equals(NORMAL)) {
					float x = Float.parseFloat(parts.nextToken());
					float y = Float.parseFloat(parts.nextToken());
					float z = Float.parseFloat(parts.nextToken());
					normals.add(new Vector3(x, y, z));
				} /*
				 * else if (type.equals(MATERIAL_LIB)) {
				 * readMaterialLib(parts.nextToken()); } else if
				 * (type.equals(USE_MATERIAL)) { currentMaterialKey =
				 * parts.nextToken(); } else if (type.equals(OBJECT)) { String
				 * objName = parts.hasMoreTokens() ? parts.nextToken() : "";
				 * if(firstObject) { Log.d(Min3d.TAG, "Create object " +
				 * objName); co.name = objName; firstObject = false; } else {
				 * Log.d(Min3d.TAG, "Create object " + objName); co = new
				 * ParseObjectData(vertices, texCoords, normals); co.name =
				 * objName; parseObjects.add(co); } }
				 */
			}
		} catch (IOException e) {
			e.printStackTrace();
		}

	}

	public TriangleMesh getParsedObject() {
		/*
		 * Log.d(Min3d.TAG, "Start object creation"); Object3dContainer obj =
		 * new Object3dContainer(0, 0); int numObjects = parseObjects.size();
		 * Bitmap texture = null;
		 * 
		 * if(textureAtlas.hasBitmaps()) { textureAtlas.generate(); texture =
		 * textureAtlas.getBitmap();
		 * Shared.textureManager().addTextureId(texture, textureAtlas.getId(),
		 * generateMipMap); }
		 * 
		 * for (int i = 0; i < numObjects; i++) { ParseObjectData o =
		 * parseObjects.get(i); Log.d(Min3d.TAG, "Creating object " + o.name);
		 * obj.addChild(o.getParsedObject(materialMap, textureAtlas)); }
		 * 
		 * if(textureAtlas.hasBitmaps()) { if(texture != null)
		 * texture.recycle(); } Log.d(Min3d.TAG, "Object creation finished");
		 * 
		 * cleanup();
		 * 
		 * return obj;
		 */

		TriangleMesh mesh = new TriangleMesh(vertices.size(), faces.size());
		for (int i = 0; i < vertices.size(); i++) {
			mesh.oriVerts[i] = vertices.get(i);
			normals.get(i).normalize();
			mesh.oriNormals[i] = normals.get(i); // (nbNormals = nbVerts)
		}
		for (int j = 0; j < faces.size(); j++) {
			mesh.triangles[j][0] = faces.get(j).verts.get(0);
			mesh.triangles[j][1] = faces.get(j).verts.get(1);
			mesh.triangles[j][2] = faces.get(j).verts.get(2);
		}
		
		mesh.setWorldMatrix(Matrix.identity());

		return mesh;
	}

	/*
	 * private void readMaterialLib(String libID) { StringBuffer resourceID =
	 * new StringBuffer(packageID); StringBuffer libIDSbuf = new
	 * StringBuffer(libID); int dotIndex = libIDSbuf.lastIndexOf("."); if
	 * (dotIndex > -1) libIDSbuf = libIDSbuf.replace(dotIndex, dotIndex + 1,
	 * "_");
	 * 
	 * resourceID.append(":raw/"); resourceID.append(libIDSbuf.toString());
	 * 
	 * InputStream fileIn = resources.openRawResource(resources.getIdentifier(
	 * resourceID.toString(), null, null)); BufferedReader buffer = new
	 * BufferedReader( new InputStreamReader(fileIn)); String line; String
	 * currentMaterial = "";
	 * 
	 * try { while ((line = buffer.readLine()) != null) { String[] parts =
	 * line.split(" "); if (parts.length == 0) continue; String type = parts[0];
	 * 
	 * if (type.equals(NEW_MATERIAL)) { if (parts.length > 1) { currentMaterial
	 * = parts[1]; materialMap.put(currentMaterial, new Material(
	 * currentMaterial)); } } else if(type.equals(DIFFUSE_COLOR) &&
	 * !type.equals(DIFFUSE_TEX_MAP)) { Color4 diffuseColor = new
	 * Color4(Float.parseFloat(parts[1]) * 255.0f, Float.parseFloat(parts[2]) *
	 * 255.0f, Float.parseFloat(parts[3]) * 255.0f, 255.0f);
	 * materialMap.get(currentMaterial).diffuseColor = diffuseColor; } else if
	 * (type.equals(DIFFUSE_TEX_MAP)) { if (parts.length > 1) {
	 * materialMap.get(currentMaterial).diffuseTextureMap = parts[1];
	 * StringBuffer texture = new StringBuffer(packageID);
	 * texture.append(":drawable/");
	 * 
	 * StringBuffer textureName = new StringBuffer(parts[1]); dotIndex =
	 * textureName.lastIndexOf("."); if (dotIndex > -1)
	 * texture.append(textureName.substring(0, dotIndex)); else
	 * texture.append(textureName);
	 * 
	 * int bmResourceID = resources.getIdentifier(texture .toString(), null,
	 * null); Bitmap b = Utils.makeBitmapFromResourceId(bmResourceID);
	 * textureAtlas.addBitmapAsset(new BitmapAsset(currentMaterial,
	 * texture.toString())); } } } } catch (IOException e) {
	 * e.printStackTrace(); } }
	 * 
	 * @Override protected void cleanup() { super.cleanup();
	 * materialMap.clear(); }
	 */
	// private class ObjFace {
	// public ObjFace(String line, String materialKey, int faceLength) {
	// boolean emptyVt = line.indexOf("//") > -1;
	// if (emptyVt)
	// line = line.replace("//", "/");
	// StringTokenizer parts = new StringTokenizer(line);
	// parts.nextToken();
	// StringTokenizer subParts = new StringTokenizer(parts.nextToken(), "/");
	// int partLength = subParts.countTokens();
	// boolean hasuv = partLength >= 2 && !emptyVt;
	// boolean hasn = partLength == 3 || (partLength == 2 && emptyVt);
	//
	// int[] v = new int[faceLength];
	//
	// if (hasuv)
	// uv = new int[faceLength];
	// if (hasn)
	// int[] n = new int[faceLength];
	//
	// for (int i = 1; i < faceLength + 1; i++) {
	// if (i > 1)
	// subParts = new StringTokenizer(parts.nextToken(), "/");
	//
	// // int index = i - 1; v[index] = (short)
	// // (Short.parseShort(subParts.nextToken()) - 1); if (hasuv)
	// // uv[index] =
	// // (short) (Short.parseShort(subParts.nextToken()) - 1); if
	// // (hasn) n[index]
	// // = (short) (Short.parseShort(subParts.nextToken()) - 1);
	// }
	// }
	// }

}
